//
//  FXMethodEvent.swift
//  FXEvent
//
//  Created by Fanxx on 2021/11/23.
//

#if canImport(Aspects)

import Foundation
import BasicExtensions
import Aspects

/// 监听方法，调用方法的参数会以[Any]的形式返回
open class FXMethodEvent<ObjectType: NSObject>: FXEvent<[Any]?> {
    public init(for object: ObjectType, method selector: Selector, argumentsRequired: Bool = false) {
        super.init()
        let wrappedBlock: @convention(block) (AspectInfo) -> Void = { [weak self] aspectInfo in
            self?.sendActions(for: argumentsRequired ? aspectInfo.arguments() : nil)
        }
        let block: AnyObject = unsafeBitCast(wrappedBlock, to: AnyObject.self)
        _ = try? object.aspect_hook(selector, with: [], usingBlock: block)
    }
    public init(for object: ObjectType.Type, method selector: Selector, argumentsRequired: Bool = false) {
        super.init()
        let wrappedBlock: @convention(block) (AspectInfo) -> Void = { [weak self] aspectInfo in
            self?.sendActions(for: argumentsRequired ? aspectInfo.arguments() : nil)
        }
        let block: AnyObject = unsafeBitCast(wrappedBlock, to: AnyObject.self)
        _ = try? ObjectType.aspect_hook(selector, with: [], usingBlock: block)
    }
}

/// 在获取事件时动态添加及缓存要获取的事件
public struct FXMethodCalledEventsWrapper<ObjectType: NSObject> {
    let _fXMethodCalledEventsWrapObject: ObjectType
    public init(_ base: ObjectType) {
        self._fXMethodCalledEventsWrapObject = base
    }
    /// 线程安全
    public func `for`(_ selector: Selector) -> FXMethodEvent<ObjectType> {
        let key = "__fxMethodCalledEventsWrapper_\(selector)"
        return self._fXMethodCalledEventsWrapObject.extend.object(for: key, createIfNil: FXMethodEvent(for: self._fXMethodCalledEventsWrapObject, method: selector, argumentsRequired: true))
    }
}
public protocol FXMethodCalledEventable: NSObject {
}
extension FXMethodCalledEventable {
    /// 可通过此扩展来添加属性变化通知
    public var methodCalled: FXMethodCalledEventsWrapper<Self> {
        return .init(self)
    }
}
extension NSObject: FXMethodCalledEventable {
}

#endif
